home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / archives / com / internet / stik / gls002b5.zoo / memdemon.c < prev    next >
C/C++ Source or Header  |  1997-09-21  |  8KB  |  324 lines

  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <osbind.h>
  4. #define DAEMON            /* to get "int caller_pid, " */
  5. #include "global.h"
  6.  
  7. #define POOLSIZE_DEFAULT    50000L
  8. #define POOLSIZE_VAR        "ALLOCMEM"
  9. #define MIN_CHUNK        (sizeof(chunk_header) + 8)
  10. #define ALLOCED            0xAB000000UL
  11. #define FREED            0xFB000000UL
  12.  
  13. #define round(n)        (((n) + 7) & ~7)
  14. #define is_alloced(H)        (((H)->size & 0xFF000000L) == ALLOCED)
  15. #define is_freed(H)        (((H)->size & 0xFF000000L) == FREED)
  16. #define chunksize(H)        ((H)->size & 0x00FFFFFFL)
  17.  
  18. typedef struct chunk_header {
  19.   struct chunk_header *next;
  20.   unsigned long size;
  21. } chunk_header;
  22.  
  23. static unsigned char *pool = 0;
  24. static unsigned long poolsize = POOLSIZE_DEFAULT;
  25. static chunk_header *arena;
  26.  
  27. extern int daemon_pid;        /* from transdmn.c */
  28.  
  29.  
  30. int init_mem(void)
  31. {
  32.   register char *s = do_getvstr(daemon_pid, POOLSIZE_VAR);
  33.  
  34.   if (Psem_create(ARENA_SEM) < 0) {
  35.     Cconws("Unable to create arena semaphore\r\n");
  36.     return 0;
  37.   }
  38.   /* We own semaphores when they're created; release them so we can
  39.      grab them later. */
  40.   Psem_release(ARENA_SEM);
  41.  
  42.   if (s)
  43.     poolsize = strtoul(s, NULL, 0);
  44.   if (poolsize <= MIN_CHUNK) {
  45.     Cconws("alloc pool size too small - using default size\r\n");
  46.     poolsize = POOLSIZE_DEFAULT;
  47.   }
  48.   pool = (unsigned char *)Mxalloc(poolsize, 0x2B); /* global, prefer TT RAM */
  49.   if (!pool) {
  50.     Cconws("Unable to allocate alloc pool\r\n");
  51.     return 0;
  52.   }
  53.   arena = (chunk_header *)pool;
  54.   arena->next = 0;
  55.   arena->size = (poolsize - sizeof(chunk_header)) | FREED;
  56.   return 1;
  57. }
  58.  
  59.  
  60. /* join_next() -- Joins chunk |H| with the next block and sets its state to
  61.    |state|.  WARNING:  Assumes |H->next| is not NULL. */
  62. static void join_next(register chunk_header *H, unsigned long state)
  63. {
  64.   register chunk_header *H2 = H->next;
  65.   H->next = H2->next;
  66.   H->size = (chunksize(H) + chunksize(H2) + sizeof(chunk_header)) | state;
  67. }
  68.  
  69. /* try_split() -- split chunk |block| into two chunks, the first of size
  70.    |newsize|, if there's room for a second chunk.  The new chunk (if
  71.    any) is marked FREED; the (possibly smaller) original block is marked
  72.    ALLOCED.  WARNING:  assumes |newsize| is already round()'ed. */
  73. static void try_split(chunk_header *block, unsigned long newsize)
  74. {
  75.   register chunk_header *H;
  76.  
  77.   if (chunksize(block) - newsize >= MIN_CHUNK) {
  78.     H = (chunk_header *)((unsigned char *)(block + 1) + newsize);
  79.     H->next = block->next;
  80.     H->size = (chunksize(block) - newsize - sizeof(chunk_header)) | FREED;
  81.     block->next = H;
  82.     block->size = newsize | ALLOCED;
  83.  
  84.     /* if the next block is free, merge the new block into it */
  85.     if (H->next && is_freed(H->next))
  86.       join_next(H, FREED);
  87.   } else {
  88.     block->size = chunksize(block) | ALLOCED;
  89.   }
  90. }
  91.  
  92. #if 0
  93. extern int caller_pid;        /* from transdmn.c */
  94. #endif
  95.  
  96. char* do_KRmalloc(int caller_pid, int32 size)
  97. {
  98.   register chunk_header *H;
  99.  
  100.   size = round(size);
  101.   if (size >= 0x01000000L || size == 0) {
  102. #ifdef DEBUG
  103.     LOG(caller_pid, DBG_ERROR, "KRmalloc(%l) returns 0", size);
  104. #if 0
  105.     debug("sls", "KRmalloc(", size, ") returns 0");
  106. #endif
  107. #endif
  108.     return 0;
  109.   }
  110.  
  111.   Psem_obtain(ARENA_SEM);
  112.  
  113.   for (H = arena; H; H = H->next) {
  114.     if (!is_freed(H) || chunksize(H) < size)
  115.       continue;
  116.     try_split(H, size);
  117. #ifdef DEBUG
  118.     LOG(caller_pid, DBG_SYSCALL, "KRmalloc(%l) returns %p",
  119.     size, (void *)(H+1));
  120. #if 0
  121.     debug("slsp", "KRmalloc(", size, ") returns ", (void *)(H+1));
  122. #endif
  123. #endif
  124.     return (char *)(H + 1);
  125.   }
  126.  
  127.   Psem_release(ARENA_SEM);
  128.  
  129. #ifdef DEBUG
  130.   LOG(caller_pid, DBG_ERROR, "KRmalloc(%l) returns 0", size);
  131. #if 0
  132.   debug("sls", "KRmalloc(", size, ") returns 0");
  133. #endif
  134. #endif
  135.   return 0;
  136. }
  137.  
  138. void do_KRfree(int caller_pid, void *mem)
  139. {
  140.   register chunk_header *H = (chunk_header *)mem;
  141.  
  142. #ifdef DEBUG
  143.   LOG(caller_pid, DBG_SYSCALL, "Entering KRfree(%p)", mem);
  144. #if 0
  145.   debug("sps", "in KRfree(", mem, ")");
  146. #endif
  147. #endif
  148.   if (!mem)
  149.     return;
  150.  
  151.   H--;        /* step back to the header */
  152.   if (!is_alloced(H)) {
  153. #ifdef DEBUG
  154.     LOG(caller_pid, DBG_ERROR,
  155.     "In KRfree(%p):  block not allocated by KR{m,re}alloc()", mem);
  156. #if 0
  157.     debug("s", "\tblock not alloced?");
  158. #endif
  159. #endif
  160.     return;
  161.   }
  162.  
  163.   H->size = chunksize(H) | FREED;
  164.  
  165.   Psem_obtain(ARENA_SEM);
  166.  
  167.   if (H->next && is_freed(H->next)) {
  168.     /* next block is free; merge with it */
  169.     join_next(H, FREED);
  170.   }
  171.  
  172.   if (H != arena) {
  173.     /* there is a previous chunk; merge with it if it's freed */
  174.     register chunk_header *H2;
  175.  
  176.     for (H2 = arena; H2 && H2->next != H; H2 = H2->next)
  177.       continue;
  178.     if (!H2) {    /* this shouldn't happen */
  179. #ifdef DEBUG
  180.       LOG(caller_pid, DBG_ERROR,
  181.       "In KRfree(%p):  cannot find block in arena", mem);
  182. #if 0
  183.       debug("s", "\tno previous block?");
  184. #endif
  185. #endif
  186.     } else {
  187.       if (is_freed(H2)) {
  188.     join_next(H2, FREED);
  189.     H = H2;
  190.       }
  191.     }
  192.   }
  193.  
  194.   Psem_release(ARENA_SEM);
  195.  
  196. #ifdef DEBUG
  197.   LOG(caller_pid, DBG_SYSCALL, "Exiting KRfree(%p)", mem);
  198. #if 0
  199.   debug("s", "\tdone");
  200. #endif
  201. #endif
  202. }
  203.  
  204. int32 do_KRgetfree(int caller_pid, int16 flag)
  205. {
  206.   register chunk_header *H;
  207.   register unsigned long size = 0;
  208.  
  209. #ifdef DEBUG
  210.   LOG(caller_pid, DBG_SYSCALL, "Entering KRgetfree(%d)", flag);
  211. #if 0
  212.   debug("s", "in KRgetfree()");
  213. #endif
  214. #endif
  215.  
  216.   Psem_obtain(ARENA_SEM);
  217.  
  218.   if (flag) {
  219.     for (H = arena; H; H = H->next) {
  220.       if (is_freed(H) && chunksize(H) > size)
  221.     size = chunksize(H);
  222.     }
  223.   } else {
  224.     for (H = arena; H; H = H->next) {
  225.       if (is_freed(H))
  226.     size += chunksize(H);
  227.     }
  228.   }
  229.  
  230.   Psem_release(ARENA_SEM);
  231.  
  232. #ifdef DEBUG
  233.   LOG(caller_pid, DBG_SYSCALL, "KRgetfree(%d) returns %l", flag, size);
  234. #endif
  235.   return size;
  236. }
  237.  
  238. char* do_KRrealloc(int caller_pid, char *mem, int32 newsize)
  239. {
  240.   register chunk_header *H = (chunk_header *)mem;
  241.  
  242. #ifdef DEBUG
  243.   LOG(caller_pid, DBG_SYSCALL, "Entering KRrealloc(%p, %l)", mem, newsize);
  244. #if 0
  245.   debug("s", "in KRrealloc()");
  246. #endif
  247. #endif
  248.   if (!mem) {
  249.     void *newmem = do_KRmalloc(caller_pid, newsize);
  250.     if (newmem)
  251.       memset(newmem, 0, newsize);
  252. #ifdef DEBUG
  253.     LOG(caller_pid, (mem ? DBG_SYSCALL : DBG_ERROR),
  254.     "KRrealloc(%p, %l) returns %p", mem, newsize, newmem);
  255. #endif
  256.     return newmem;
  257.   }
  258.  
  259.   if (newsize == 0) {
  260.     do_KRfree(caller_pid, mem);
  261. #ifdef DEBUG
  262.     LOG(caller_pid, DBG_SYSCALL,
  263.     "KRrealloc(%p, %l) returns 0", mem, newsize);
  264. #endif
  265.     return 0;
  266.   }
  267.  
  268.   H--;        /* step back to the header */
  269.   if (!is_alloced(H))
  270.     return 0;
  271.  
  272.   newsize = round(newsize);
  273.   if (newsize <= chunksize(H)) {
  274.     Psem_obtain(ARENA_SEM);
  275.  
  276.     /* if we're downsizing, we may have room to split the chunk */
  277.     try_split(H, newsize);
  278. #ifdef DEBUG
  279.     LOG(caller_pid, DBG_SYSCALL,
  280.     "KRrealloc(%p, %l) returns %p", mem, newsize, mem);
  281. #endif
  282.     return mem;
  283.   } else if (H->next && is_freed(H->next) &&
  284.              (chunksize(H) + chunksize(H->next) +
  285.                     sizeof(chunk_header)) >= newsize) {
  286.     /* Next chunk is free and big enough to accommodate the new size;
  287.        join it with the current chunk */
  288.     join_next(H, ALLOCED);
  289.     /* We may even have room to split off part of the newly joined chunk */
  290.     try_split(H, newsize);
  291.  
  292.     Psem_release(ARENA_SEM);
  293.  
  294. #ifdef DEBUG
  295.     LOG(caller_pid, DBG_SYSCALL,
  296.     "KRrealloc(%p, %l) returns %p", mem, newsize, mem);
  297. #endif
  298.     return mem;
  299.   } else {
  300.     register char *newmem = do_KRmalloc(caller_pid, newsize);
  301.  
  302.     if (!newmem) {
  303. #ifdef DEBUG
  304.       LOG(caller_pid, DBG_ERROR,
  305.       "KRrealloc(%p, %l) returns 0", mem, newsize);
  306. #endif
  307.       return 0;
  308.     }
  309.     memcpy(newmem, mem, chunksize(H));
  310.     do_KRfree(caller_pid, mem);
  311. #ifdef DEBUG
  312.     LOG(caller_pid, DBG_SYSCALL,
  313.     "KRrealloc(%p, %l) returns %p", mem, newsize, newmem);
  314. #endif
  315.     return newmem;
  316.   }
  317. }
  318.  
  319.  
  320. void cleanup_mem()
  321. {
  322.   if (pool) Mfree(pool);
  323. }
  324.